﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Text;

namespace CommonLib
{
	/// <summary>
	/// A common logging class for both the server and client.
	/// It can save the reports to a file if one is provided...
	/// Also puts reports in a table that the server interface can use
	/// </summary>
	public class Logger : IDisposable
	{
		System.IO.StreamWriter writer;
		private DataTable myLogTable;
		public DataTable LogTable
		{
			get
			{
				return this.myLogTable;
			}
		}
		private class LogTableNames
		{
			private LogTableNames()
			{
			}
			public static String LogTime = "LogTime";
			public static String LogType = "LogType";
			public static String LogMessage = "Message";
		}

		private static Logger _instance;
		public static Logger Instance
		{
			get
			{
				if (_instance == null)
					_instance = new Logger();
				return _instance;
			}
		}

		protected Logger()
		{
			this.myLogTable = new DataTable();
			this.myLogTable.Locale = System.Globalization.CultureInfo.CurrentUICulture;
			this.myLogTable.Columns.Add(LogTableNames.LogMessage, typeof(String));
			this.myLogTable.Columns.Add(LogTableNames.LogTime, typeof(DateTime));
			this.myLogTable.Columns.Add(LogTableNames.LogType, typeof(LogType));
		}
		/// <summary>
		///	Enables the logger to write to files.
		/// </summary>
		/// <param name="fileName">The filename of where to write logs</param>
		public void Start(String fileName)
		{
			if (writer != null)
				writer.Dispose();
			writer = new System.IO.StreamWriter(fileName);
		}
		/// <summary>
		/// Instructs the logger to stop writing to files
		/// </summary>
		public void Stop()
		{
			if (writer != null)
			{
				writer.Close();
				writer = null;
			}
		}
		/// <summary>
		/// Receives a report of LogType type.  The logger then
		/// tries to write this to a file.  It also adds the log
		/// to a table.
		/// 
		/// If the table gets too long, the logger prunes the oldest entries.
		/// </summary>
		/// <param name="type">The type of the log message</param>
		/// <param name="source">The source object where this report comes from</param>
		/// <param name="message">The human-readable message of the report</param>
		public void Report(LogType type, Object source, String message)
		{
			if (source == null)
				source = new object();
			DateTime now = DateTime.Now;
			if (writer != null)
			{
				writer.WriteLine(String.Format(CommonLibSettings.Default.DefaultLogFormat, now, type.ToString(), source.GetType().Name, message));
				writer.Flush();
			}
			lock (myLogTable)
			{
				DataRow newRow = myLogTable.NewRow();
				newRow[LogTableNames.LogTime] = now;
				newRow[LogTableNames.LogType] = type;
				newRow[LogTableNames.LogMessage] = message;
				myLogTable.Rows.Add(newRow);

				if (myLogTable.Rows.Count > 25)
				{
					List<DataRow> removedRows = new List<DataRow>();
					foreach (DataRow row in myLogTable.Rows)
					{
						DateTime postTime = (DateTime)row[LogTableNames.LogTime];
						if (now.Subtract(postTime).CompareTo(CommonLibSettings.Default.LogTableTimeout) > 0)
						{
							removedRows.Add(row);
						}
					}
					foreach (DataRow row in removedRows)
					{
						myLogTable.Rows.Remove(row);
					}
				}
			}
		}

		#region IDisposable Members

		public void Dispose()
		{
			this.myLogTable.Dispose();
			this.writer.Dispose();
		}

		#endregion
	}
	/// <summary>
	/// Represents the type of the log report.
	/// </summary>
	public enum LogType
	{
		/// <summary>
		/// Something occurs that shouldn't
		/// </summary>
		Error,
		/// <summary>
		/// Something from the client that's routine,
		/// like an announcement or resource transfer
		/// </summary>
		Event,
		/// <summary>
		/// Something from the server that's routine,
		/// like a background thread running
		/// </summary>
		Information,
	}
}
